package com.example.demo.jackson;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class TypeBeanPropertyFilter implements PropertyFilter {

    private final Map<Class<?>, Set<String>> classExcludePropertiesMap;

    private TypeBeanPropertyFilter(Map<Class<?>, Set<String>> classExcludePropertiesMap) {
        this.classExcludePropertiesMap = Collections.unmodifiableMap(classExcludePropertiesMap);
    }

    private boolean include(Object pojo, PropertyWriter writer) {
        return !this.classExcludePropertiesMap
                .getOrDefault(pojo.getClass(), Collections.emptySet())
                .contains(writer.getName());
    }

    @Override
    public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider prov, PropertyWriter writer) throws Exception {
        if (include(pojo, writer)) {
            writer.serializeAsField(pojo, gen, prov);
        } else if (!gen.canOmitFields()) {
            writer.serializeAsOmittedField(pojo, gen, prov);
        }
    }

    @Override
    public void serializeAsElement(Object elementValue, JsonGenerator gen, SerializerProvider prov, PropertyWriter writer) throws Exception {
        writer.serializeAsElement(elementValue, gen, prov);
    }

    @Override
    @Deprecated
    public void depositSchemaProperty(PropertyWriter writer, ObjectNode propertiesNode, SerializerProvider provider) throws JsonMappingException {
        writer.depositSchemaProperty(propertiesNode, provider);
    }

    @Override
    public void depositSchemaProperty(PropertyWriter writer, JsonObjectFormatVisitor objectVisitor, SerializerProvider provider) throws JsonMappingException {
        writer.depositSchemaProperty(objectVisitor, provider);
    }

    public static TypeBeanPropertyFilterBuilder builder() {
        return new TypeBeanPropertyFilterBuilder();
    }

    public static class TypeBeanPropertyFilterBuilder {

        private final Map<Class<?>, Set<String>> classExcludePropertiesMap = new HashMap<>();

        public TypeBeanPropertyFilterBuilder excludeClassProperties(Class<?> clazz, String... properties) {
            Set<String> excludePropertiesSet = classExcludePropertiesMap.computeIfAbsent(clazz, k -> new HashSet<>());
            Collections.addAll(excludePropertiesSet, properties);
            return this;
        }

        public TypeBeanPropertyFilter build() {
            return new TypeBeanPropertyFilter(this.classExcludePropertiesMap);
        }

    }

}
